#include "McuManager.h"
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include "Utils.h"
#include "VanException.h"

McuManager* McuManager::m_pInstance = NULL;

McuManager::McuManager()
{
	m_Uart.SetOnRecv(this);
	m_Parser.SetOnPacket(this);

	m_ReqCmd = -1;
	m_pRespPacket = NULL;
	m_pHandler = McuHandler::Instance();
	
	sem_init(&m_hSem, 0, 0);	
}

McuManager::~McuManager()
{
	Close();
	sem_post(&m_hSem);

	sem_destroy(&m_hSem);
}

McuManager* McuManager::Instance()
{
	if (NULL == m_pInstance) {
		m_pInstance = new McuManager();
	}

	return m_pInstance;
}

bool McuManager::Open()
{
	Close();

	return m_Uart.Open("/dev/ttyHSL1", B921600);
}

void McuManager::Close()
{
	m_Uart.Close();
}

bool McuManager::IsOpen()
{
	return m_Uart.IsOpen();
}

void McuManager::OnRecv(const byte* pBuf, int length)
{
	m_Parser.Parse(pBuf, length);
}

int McuManager::Wait(int timeout)
{
	struct timespec ts;

    if (clock_gettime(CLOCK_REALTIME, &ts) < 0) {
		return -1;
	}

    ts.tv_sec  += timeout/1000;
    ts.tv_nsec += timeout%1000*1000000;

    return sem_timedwait(&m_hSem, &ts);
}

Packet* McuManager::Request(Packet* pPacket, bool wait)
{
	if (!IsOpen()) {
		throw new VanException(EC_NOT_CONNECTED);
	}

	m_Lock.Lock();
	VanException* pException = NULL;

	try {
		RequestInner(pPacket, wait);
	} catch (VanException* e) {
		pException = e;
	}

	m_ReqCmd = -1;
	m_Lock.Unlock();

	if (NULL != pException) {
		throw pException;
	}

	if (NULL != m_pRespPacket
		&& 0x81 == m_pRespPacket->GetCMD()) 
	{
		int result = m_pRespPacket->GetBody()[1];

		m_pRespPacket = NULL;
		int exception = 0;

		switch (result) {
			case 1:
				exception = EC_EXCUTE_FAILED;
				break;
			case 2:
				exception = EC_MSG_ERROR;
				break;
			case 3:
				exception = EC_UNSUPPORTED;
				break;
		}

		if (0 != exception) {
			throw new VanException(exception);
		}
	}

	return m_pRespPacket;
}

Packet* McuManager::RequestInner(Packet* pPacket, bool wait)
{
	pPacket->Build();
	m_pRespPacket = NULL;
	m_ReqCmd = pPacket->GetCMD();

	int length = m_Uart.Write(pPacket->GetBuffer(), pPacket->GetLength());

	if (length < pPacket->GetLength()) {
		throw new VanException(EC_SEND_FAILED);
	}

	if (m_ReqCmd>=0x80 || !wait) {
		return NULL;
	}

	int result = Wait(2000);

	if (0 != result) {
		if (ETIMEDOUT == errno) {
			throw new VanException(EC_RESP_TIMEOUT);
		} else {
			throw new VanException(EC_UNKNOWN);
		}
	}

	return m_pRespPacket;
}

void McuManager::OnPacket(Packet* pPacket)
{
	int nCmd = pPacket->GetCMD();

	if (nCmd < 128) 
	{
		m_pHandler->Handle(pPacket);
	}else if (-1 != m_ReqCmd)
	{
		if ((0x81==nCmd && m_ReqCmd==pPacket->GetBody()[0])
			|| (nCmd-128 == m_ReqCmd))
		{
			m_pRespPacket = pPacket;
			sem_post(&m_hSem);
		}

	}
}
